home *** CD-ROM | disk | FTP | other *** search
/ BBS in a Box 15 / BBS in a box XV-2.iso / Files II / Prog / B-C / Control Panel 0.9.5.sit / Control Panel Project 0.9.5 / ShowIconFamily.c / ShowIconFamily.c
Encoding:
C/C++ Source or Header  |  1994-10-06  |  9.9 KB  |  363 lines  |  [TEXT/KAHL]

  1. /*
  2.     ShowIconFamily.c
  3.     
  4.     ShowINIT compatible routine that shows 'ICN#' and 'iclx' flavor icons.
  5.     For use by all INITs in System 7 and beyond.
  6.     
  7.     by Patrick C. Beard.
  8.     modified by James W. Walker for compatibility with IconWrap 1.2,
  9.     and for use as a separate code resource.
  10.     
  11.     Modified 11/19/93 by Ken Worley to remove any necessity for statics and
  12.     globals.  No longer requires A4 register to be set up.
  13.     
  14.     Instructions for use:
  15.     
  16.         • Create a family of icons with ResEdit 2.1 or later.  This will
  17.             include 'ICN#', 'icl4', & 'icl8' icons.
  18.         
  19.         To use within a larger INIT project:
  20.             • #define SEPARATE_CODE 0  below.
  21.             • Use SetUpA4 to set up Think C globals.    ** not required - kw **
  22.             • Call ShowIconFamily() with the resource id of the family
  23.                 that you used.
  24.         
  25.         To use as a separate code resource:
  26.             • #define SEPARATE_CODE 1  below.
  27.             • Set the project type to code resource, set the code type
  28.                 and resource ID (I use type 'Code', ID -4048 for cdevs),
  29.                 compile and merge into your INIT or cdev file.
  30.             • In your main INIT code, call ShowIconFamily like so:
  31.                 show_init = GetResource( 'Code', -4048 );
  32.                 HLock( show_init );
  33.                 CallPascal( icon_family_ID, *show_init );
  34.                 HUnlock( show_init );
  35.  
  36.     Enhancements:
  37.         
  38.         • Uses 'iclx' & 'ICN#' icons from the Finder's "icon family" in System 7.
  39.         • Generates a position for icons that is guaranteed to be on screen, while
  40.           remaining compatible with previous releases of ShowInit.
  41.     
  42.     This code is completely public domain.  Let's hope this becomes a new standard.
  43.     
  44.     This code is derived from the original ShowInit by Paul Mercer, Darin Adler,
  45.     Paul Snively, and Steve Capps.
  46.     
  47.     Special thanks to Ben Haller & Rob Vaterlaus for valuable suggestions and help.
  48.  */
  49.  
  50. #define SEPARATE_CODE    0
  51.  
  52. #if SEPARATE_CODE
  53. #include <SetUpA4.h>    /* JWW */
  54. #endif
  55.  
  56. #ifndef nil
  57. #define nil ((void*)0L)
  58. #endif
  59. #ifndef topLeft
  60. #define topLeft(r) ((Point*)&r)[0])
  61. #endif
  62. #ifndef botRight
  63. #define botRight(r) ((Point*)&r)[1])
  64. #endif
  65.  
  66. typedef struct qdGlobals {
  67.     char privates[76];
  68.     long randSeed;
  69.     BitMap screenBits;
  70.     Cursor arrow;
  71.     Pattern dkGray;
  72.     Pattern ltGray;
  73.     Pattern gray;
  74.     Pattern black;
  75.     Pattern white;
  76.     GrafPtr thePort;
  77.     long    end;
  78. } qdGlobals;
  79.  
  80. /* Prototypes */
  81.  
  82. static short    CheckSum( register short x );
  83. static void        GetIconRect( register Rect* iconRect, GrafPtr port );
  84. static void        Next_position( void );
  85. static void        DrawBWIcon( short iconId, GrafPtr port );
  86. static Handle    ChooseIcon( short iconId, short* suggestedDepth );
  87. static void        DrawColorIcon( short iconId, CGrafPtr port, short theDepth );
  88.  
  89. /* this is where it all happens. */
  90.  
  91. #if SEPARATE_CODE
  92. void main(short iconId)
  93. #else
  94. void ShowIconFamily(short iconId)
  95. #endif
  96. {
  97.     long        oldA5;
  98.     qdGlobals    qd;                    /* our QD globals. */
  99.     SysEnvRec    environment;        /* machine configuration. */
  100.     CGrafPort    gp;                    /* our grafport. */
  101.     short        theDepth;            /* the depth the monitor is in */    /* kw */
  102.     
  103. #if SEPARATE_CODE
  104.     RememberA0(); /* JWW */
  105.     SetUpA4(); /* JWW */
  106. #endif
  107.     
  108.     /* get a value for A5, a structure that mirrors qd globals. */
  109.     oldA5 = SetA5((long)&qd.end);
  110.     InitGraf(&qd.thePort);
  111.     
  112.     /* find out what kind of machine this is. */
  113.     SysEnvirons(curSysEnvVers, &environment);
  114.     if (environment.hasColorQD) {
  115.         theDepth = (**(**GetMainDevice()).gdPMap).pixelSize;
  116.         if (theDepth < 4)
  117.             theDepth = 1;
  118.     } else {
  119.         theDepth = 1;
  120.     }
  121.  
  122.     /* see what type of port to open. */
  123.     if (theDepth >= 4) {
  124.         OpenCPort(&gp);
  125.     } else {
  126.         OpenPort((GrafPtr)&gp);
  127.     }
  128.     
  129.     if (theDepth == 1)
  130.         DrawBWIcon( iconId, (GrafPtr)&gp );
  131.     else
  132.         DrawColorIcon( iconId, &gp, theDepth );
  133.     
  134.     Next_position(); /* JWW */
  135.  
  136.     SetA5(oldA5);
  137. #if SEPARATE_CODE
  138.     RestoreA4();
  139. #endif
  140. }
  141.  
  142. /*
  143.     ShowInit's information is nestled at the tail end of CurApName.
  144.     It consists of a short which encodes the next horizontal offset,
  145.     and another short which is that value checksummed with the function below.
  146.  */
  147.  
  148. #define CurApName_LM    0x910
  149. #define ShowINITTable ((short*)(CurApName_LM + 32 - 4))
  150. #define CheckSumConst 0x1021        /* magic value to check-sum with. */
  151.  
  152. #define InitialXPosition 8            /* initial horizontal offset. */
  153. #define YOffset            40            /* constant from bottom to place the icon. */
  154. #define XOffset            40            /* amount to change it by. */
  155.  
  156. /* CheckSum() computes the magic value to determine if ShowInit's have run already. */
  157.  
  158. static short CheckSum(register short x)
  159. {
  160.     asm {
  161.         rol.w    #1, x
  162.     }
  163.     return (x ^ CheckSumConst);
  164. }
  165.  
  166. /*
  167.     GetIconRect() generates an appropriate rectangle to display the
  168.     next INIT's icon in.
  169.     It is also responsible for updating the horizontal
  170.     position in low memory.  This is a departure from
  171.     the original ShowInit code, which updates low
  172.     memory AFTER displaying the icon. -- changed by JWW
  173.     This code won't generate an icon position until it is certain that the icon can be loaded, so the
  174.     same behaviour occurs.
  175.     
  176.     This routine also generates a rectangle which is guaranteed to be onscreen.  It
  177.     does this by taking the horizontal offset modulo the screen width to generate
  178.     the horizontal position of the icon, and the offset divided by the screen
  179.     width to generate the proper row.
  180.     
  181.     kw - I modified this routine to take the extra 'port' argument.
  182.  */
  183.  
  184. static void GetIconRect(register Rect* iconRect, GrafPtr port)
  185. {
  186.     register short screenWidth = port->portRect.right - port->portRect.left;
  187.     /* if we are the first INIT to run we need to initialize the horizontal value. */
  188.     if (CheckSum(ShowINITTable[0]) != ShowINITTable[1])
  189.         ShowINITTable[0] = InitialXPosition;
  190.     
  191.     /* compute top left of icon's rect. */
  192.     iconRect->left = (ShowINITTable[0] % screenWidth);
  193.     iconRect->top = port->portRect.bottom - YOffset * (1 + (ShowINITTable[0] / screenWidth));
  194.     iconRect->right = iconRect->left + 32;
  195.     iconRect->bottom = iconRect->top + 32;
  196.     
  197. }
  198.  
  199. /*
  200.     JWW: In Beard's original version, this was done at the end of
  201.     GetIconRect. That caused incorrect behavior when IconWrap 1.2 was
  202.     used to wrap icons.  Namely, if an INIT using that version of
  203.     ShowIconFamily was the first in a row, then the second icon in that
  204.     row would land on top of it.
  205. */
  206. static void Next_position( void )
  207. {
  208.     /* advance the position for the next icon. */
  209.     ShowINITTable[0] += XOffset;
  210.     
  211.     /* recompute the checksum. */
  212.     ShowINITTable[1] = CheckSum(ShowINITTable[0]);    
  213. }
  214.  
  215. /* DrawBWIcon() draws the 'ICN#' member of the icon family. */
  216. /* kw - I modified this routine to take the extra 'port' argument. */
  217.  
  218. static void DrawBWIcon(short iconId, GrafPtr port)
  219. {
  220.     Handle icon;
  221.     Rect iconRect;
  222.     BitMap source, destination;
  223.     
  224.     icon = Get1Resource('ICN#', iconId);
  225.     if (!icon)
  226.         return;
  227.     HLock(icon);
  228.     
  229.     GetIconRect(&iconRect, port);
  230.  
  231.     /* prepare the source and destination bitmaps. */
  232.     source.baseAddr = *icon + 128;                    /* mask address. */
  233.     source.rowBytes = 4;
  234.     SetRect(&source.bounds, 0, 0, 32, 32);
  235.     destination = port->portBits;
  236.     
  237.     /* transfer the mask. */
  238.     CopyBits(&source, &destination, &source.bounds, &iconRect, srcBic, nil);
  239.     
  240.     /* and the icon. */
  241.     source.baseAddr = *icon;    
  242.     CopyBits(&source, &destination, &source.bounds, &iconRect, srcOr, nil);
  243.     
  244.     ReleaseResource(icon);
  245. }
  246.  
  247. /*
  248.     ChooseIcon() chooses the optimal icon for the current screen depth.
  249.     
  250.     Priorities for choosing icons:
  251.         1. match the bit depth to the icon.
  252.         2. use alternate bit depth version if available.
  253.         3. draw the black & white version.
  254.  */
  255.     
  256. static Handle ChooseIcon(short iconId, short* suggestedDepth)
  257. {
  258.     short depth = *suggestedDepth;
  259.     Handle icon = nil;
  260.  
  261.     if (depth == 4) {
  262.         icon = Get1Resource('icl4', iconId);
  263.         if (!icon) {
  264.             /* try alternate depth. */
  265.             icon = Get1Resource('icl8', iconId);
  266.             if (icon)
  267.                 depth = 8;
  268.         }
  269.     } else {
  270.         depth = 8;
  271.         icon = Get1Resource('icl8', iconId);
  272.         if (!icon) {
  273.             /* try alternate depth. */
  274.             icon = Get1Resource('icl4', iconId);
  275.             if (icon)
  276.                 depth = 4;
  277.         }
  278.     }
  279.     
  280.     *suggestedDepth = depth;
  281.     return icon;
  282. }
  283.  
  284. /* DrawColorIcon() draws the appropriate icon for the current screen depth. */
  285. /* kw - I modified this routine to take the extra arguments 'port' and 'theDepth' */
  286.  
  287. static void DrawColorIcon(short iconId, CGrafPtr port, short theDepth)
  288. {
  289.     short depthToUse;
  290.     Handle mask, icon;
  291.     CTabHandle clut;
  292.     PixMapHandle source;
  293.     BitMap maskBits;
  294.     long rowBytes;
  295.     Rect iconRect, bounds;
  296.     
  297.     /* by default we will be using the actual depth of the screen. */
  298.     depthToUse = theDepth;
  299.     icon = ChooseIcon(iconId, &depthToUse);
  300.     
  301.     /* if no color icon available, draw the black & white icon. */
  302.     if (!icon) {
  303.         DrawBWIcon(iconId, (GrafPtr)port);
  304.         return;
  305.     }
  306.     HLock(icon);
  307.     
  308.     /* get the black & white icon to get the mask drawn. */
  309.     mask = Get1Resource('ICN#', iconId);
  310.     if (!mask)
  311.         return;
  312.     HLock(mask);
  313.  
  314.     /* get the correct color lookup table. */
  315.     clut = GetCTable(depthToUse);
  316.     if (!clut)
  317.         return;
  318.     
  319.     /* create a pixmap to stick the icon bits into for screen blitting. */
  320.     source = NewPixMap();
  321.     if (!source) {
  322.         DisposCTable(clut);
  323.         return;
  324.     }
  325.     
  326.     /* set up the source pixmap with the appropriate bounds, depth, and clut. */
  327.     bounds.top = bounds.left = 0;
  328.     bounds.bottom = bounds.right = 32;
  329.     rowBytes = (((depthToUse * 32) + 15) / 16) * 2;
  330.     (**source).baseAddr = *icon;
  331.     (**source).rowBytes = ((short)rowBytes) | 0x8000;
  332.     (**source).bounds = bounds;
  333.     (**source).pixelType = 0;            /* chunky model. */
  334.     (**source).pixelSize = depthToUse;
  335.     (**source).cmpCount = 1;            /* if in 32 bit mode this will be 3, so must change. */
  336.     (**source).cmpSize = depthToUse;    /* only chunky images used. */
  337.     DisposCTable((**source).pmTable);    /* dispose of default, uninitialized table. */
  338.     (**source).pmTable = clut;
  339.  
  340.     /* get position to draw icon in. */
  341.     GetIconRect(&iconRect, (GrafPtr)port);
  342.  
  343.     /* prepare the mask bitmap. */
  344.     maskBits.baseAddr = *mask + 128;                    /* mask address. */
  345.     maskBits.rowBytes = 4;
  346.     maskBits.bounds = bounds;
  347.  
  348.     /* punch out the mask. */    
  349.     CopyBits(&maskBits, (BitMap*)&port->portPixMap, &bounds, &iconRect, srcBic, nil);
  350.     
  351.     /* draw the actual color icon. */
  352.     HLock((Handle)source);
  353.     CopyBits((BitMap*)*source, (BitMap*)&port->portPixMap, &bounds, &iconRect, srcOr, nil);
  354.     
  355.     /* release everything we've allocated. */
  356.     (**source).baseAddr = nil;
  357.     DisposPixMap(source);
  358.     
  359.     /* release the icon and mask. */
  360.     ReleaseResource(icon);
  361.     ReleaseResource(mask);
  362. }
  363.